package com.lecyon.farm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.lecyon.farm.base.BaseRequestPageVo;
import com.lecyon.farm.base.BaseResponse;
import com.lecyon.farm.base.RestResponse;
import com.lecyon.farm.common.CommonService;
import com.lecyon.farm.common.constant.CommonConstant;
import com.lecyon.farm.common.constant.FarmSysConstant;
import com.lecyon.farm.common.enums.SysRoleEnum;
import com.lecyon.farm.common.exception.FarmException;
import com.lecyon.farm.entity.*;
import com.lecyon.farm.mapper.FmWorkMapper;
import com.lecyon.farm.mapper.FmWorkTotalMapper;
import com.lecyon.farm.service.*;
import com.lecyon.farm.util.RedisUtils;
import com.lecyon.farm.util.ResultUtil;
import com.lecyon.farm.util.StringHelper;
import com.lecyon.farm.util.ValidateUtils;
import com.lecyon.farm.vo.query.QueryFmWorkVo;
import com.lecyon.farm.vo.view.FmStatisticDataVo;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.List;
import java.util.Set;

/**
 * <p>
 * VIEW 服务实现类
 * </p>
 *
 * @author YaoZheng
 * @since 2020-04-02
 */
@Service
@Validated
public class FmWorkTotalServiceImpl extends ServiceImpl<FmWorkTotalMapper, FmWorkTotal> implements IFmWorkTotalService {

    private static final Logger LOG = LoggerFactory.getLogger(FmWorkTotalServiceImpl.class);

    private FmWorkMapper mapper;

    private CommonService commonService;

    private IJsSysEmployeeService jsSysEmployeeService;

    private IJsSysOfficeService jsSysOfficeService;

    private IFmCarService fmCarService;

    private RedisUtils redisUtils;

    private IExcelService excelService;

    /**
     * 获取统计后的数据列表
     * 按农机号 GROUP BY
     *
     * @param vo 查询条件
     * @return 查询结果
     */
    @Override
    public RestResponse<Page<FmStatisticDataVo>> getTotalDataList(BaseRequestPageVo<QueryFmWorkVo> vo) {
        RestResponse<Page<FmStatisticDataVo>> result = new RestResponse<>();
        String token = vo.getUserToken();
        JsSysUser sysUser = commonService.findUserByToken(token);
        if (ValidateUtils.isNullOrEmpty(sysUser)) {
            return ResultUtil.error(null, CommonConstant.ASSOCIATED_DATA_MISS, "找不到登录用户相关数据");
        }
        String userCode = sysUser.getUserCode();
        QueryFmWorkVo queryCondition = vo.getEntity(QueryFmWorkVo.class);
        if (StringHelper.isEmpty(queryCondition.getType())) {
            log.warn("Method getTotalDataList invoked. But necessary condition is missed. 未指定作业类型");
            return ResultUtil.error(result, CommonConstant.EX_FORM_VALIDATE_REQUIRED, "未指定作业类型");
        }
        JsSysEmployee jsSysEmployee = jsSysEmployeeService.getById(userCode);
        String officeCode = null;
        if (ValidateUtils.isNotNullOrEmpty(jsSysEmployee) && StringHelper.isNotEmpty(jsSysEmployee.getOfficeCode())) {
            officeCode = jsSysEmployee.getOfficeCode();
        }
        QueryWrapper<FmCar> fmCarQueryWrapper = new QueryWrapper<>();
        Set<String> fmCarIdSet = Sets.newTreeSet();
        if (SysRoleEnum.MASTER.getLevel().equals(sysUser.getSign())) {
            // 机构管理员 可以看到所辖区域内所有相关信息
            // GR代表个人用户
            String specialOfficeCode = "GR";
            if (StringHelper.isNotEmpty(officeCode) && !specialOfficeCode.equals(officeCode)) {
                JsSysOffice jsSysOffice = jsSysOfficeService.getById(officeCode);
                if (ValidateUtils.isNotNullOrEmpty(jsSysOffice) && StringHelper.isNotEmpty(jsSysOffice.getParentCodes())) {
                    String parentCodes = jsSysOffice.getParentCodes();
                    if (parentCodes.contains(CommonConstant.HARDWARE_RESPONSE_SPLIT_STR)) {
                        String[] parentCode = parentCodes.split(CommonConstant.HARDWARE_RESPONSE_SPLIT_STR);
                        int codeLength = parentCode.length;
                        switch (codeLength) {
                            case 1:
                                // 省级机构
                                queryCondition.setProvince(officeCode);
                                fmCarQueryWrapper.eq("province", officeCode);
                                break;
                            case 2:
                                // 市级机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", officeCode);
                                break;
                            case 3:
                                // 区县机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(parentCode[2]);
                                queryCondition.setCounty(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", parentCode[2])
                                        .eq("county", officeCode);
                                break;
                            default:
                                // 乡镇一级机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(parentCode[2]);
                                queryCondition.setCounty(parentCode[3]);
                                queryCondition.setTowns(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", parentCode[2])
                                        .eq("county", parentCode[3]).eq("towns", officeCode);
                                break;
                        }
                    }
                }
            }
            List<FmCar> fmCarList = fmCarService.list(fmCarQueryWrapper);
            if (CollectionUtils.isNotEmpty(fmCarList)) {
                fmCarList.stream().forEach(item -> fmCarIdSet.add(item.getCarId()));
            }

        } else if (SysRoleEnum.ADMIN.getLevel().equals(sysUser.getSign())) {
            // 合作社管理员 可以看到该合作社所有相关信息
            queryCondition.setCooperationId(jsSysEmployee.getOfficeCode());
        } else if (SysRoleEnum.USER.getLevel().equals(sysUser.getSign())) {
            // 个人用户 可以看到个人上传的所有信息
            queryCondition.setUserId(sysUser.getUserCode());
        } else if (SysRoleEnum.HOST.getLevel().equals(sysUser.getSign())) {
            // 主机用户 可以看到该主机上传的所有信息
            queryCondition.setCarId(sysUser.getWxOpenid());
        }
        Page<FmStatisticDataVo> page = new Page<>(vo.getPageNum(), vo.getPageSize());
        String redisTableName = FarmSysConstant.REDIS_KEY_STATISTIC_TOTAL_WORK_DATA;
        boolean redisFlag = false;
        boolean quickSearchFlag = queryCondition.isQuickSearch();
        String type = queryCondition.getType();
        if (quickSearchFlag) {
            redisFlag = redisUtils.hHasKey(redisTableName, type);
        }
        if (redisFlag) {
            List<FmStatisticDataVo> statisticResult = (List<FmStatisticDataVo>) redisUtils.hGet(redisTableName, type);
            List<FmStatisticDataVo> resultList;
            List<FmStatisticDataVo> tempResultList = Lists.newLinkedList();
            if (CollectionUtils.isNotEmpty(statisticResult)) {
                if (StringHelper.isNotEmpty(queryCondition.getCarId()) || StringHelper.isNotEmpty(queryCondition.getCarOwner()) || StringHelper.isNotEmpty(queryCondition.getCarOwnerPhone())) {
                    String carId = queryCondition.getCarId();
                    String carOwner = queryCondition.getCarOwner();
                    String carOwnerPhone = queryCondition.getCarOwnerPhone();
                    for (FmStatisticDataVo tempFmStatisticDataVo : statisticResult) {
                        if (StringHelper.isEmpty(carId) || !carId.equals(tempFmStatisticDataVo.getCarId())) {
                            continue;
                        }
                        if (StringHelper.isEmpty(carOwner) || !carOwner.equals(tempFmStatisticDataVo.getCarOwner())) {
                            continue;
                        }
                        if (StringHelper.isEmpty(carOwnerPhone) || !carOwnerPhone.equals(tempFmStatisticDataVo.getCarOwnerPhone())) {
                            continue;
                        }
                        if (CollectionUtils.isNotEmpty(fmCarIdSet) && !fmCarIdSet.contains(tempFmStatisticDataVo.getCarId())) {
                            continue;
                        }
                        tempResultList.add(tempFmStatisticDataVo);
                    }
                } else {
                    tempResultList.addAll(statisticResult);
                }
            }
            int startIndex, endIndex;
            int pageNum = vo.getPageNum();
            int pageSize = vo.getPageSize();
            startIndex = pageSize * (pageNum - 1);
            endIndex = startIndex + pageSize;
            if (endIndex >= tempResultList.size()) {
                endIndex = tempResultList.size();
            }
            resultList = tempResultList.subList(startIndex, endIndex);
            page.setTotal(tempResultList.size());
            page.setRecords(resultList);
        } else {
            page = mapper.selectStatisticByPage(page, queryCondition);
        }
        return ResultUtil.success(result, page);
    }

    /**
     * 获取所有统计后的数据列表并加载到缓存中
     * 定时轮询
     *
     * @return 查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Scheduled(fixedRate = FarmSysConstant.SCHEDULE_FIX_RATE)
    public BaseResponse reloadTotalDataList() {
        LOG.info("定时任务{}启动", "reloadTotalDataList");
        QueryFmWorkVo queryCondition = new QueryFmWorkVo();
        List<FmStatisticDataVo> statisticResult;
        String[] types = FarmSysConstant.SYS_JOB_TYPE;
        String tableName = FarmSysConstant.REDIS_KEY_STATISTIC_TOTAL_WORK_DATA;
        boolean flag;
        for (String type : types) {
            queryCondition.setType(type);
            statisticResult = mapper.selectStatistic(queryCondition);
            flag = redisUtils.hHasKey(tableName, type);
            if (flag) {
                //删除原有list
                redisUtils.hDel(tableName, type);
            }
            flag = redisUtils.hSet(tableName, type, statisticResult);
            if (!flag) {
                throw new FarmException(CommonConstant.EX_DB_REDIS_ERROR, "缓存到Redis时发生异常");
            }
        }
        LOG.info("定时任务{}完成", "reloadTotalDataList");
        return ResultUtil.success();
    }

    /**
     * ----------------------------- 分割线 以下是setter方法，用于替换field上的@Autowired -----------------------------
     **/

    @Autowired
    public void setMapper(FmWorkMapper mapper) {
        this.mapper = mapper;
    }

    @Autowired
    @Lazy
    public void setJsSysEmployeeService(IJsSysEmployeeService jsSysEmployeeService) {
        this.jsSysEmployeeService = jsSysEmployeeService;
    }

    @Autowired
    @Lazy
    public void setRedisUtils(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    @Autowired
    @Lazy
    public void setCommonService(CommonService commonService) {
        this.commonService = commonService;
    }

    @Autowired
    @Lazy
    public void setJsSysOfficeService(IJsSysOfficeService jsSysOfficeService) {
        this.jsSysOfficeService = jsSysOfficeService;
    }

    @Autowired
    @Lazy
    public void setFmCarService(IFmCarService fmCarService) {
        this.fmCarService = fmCarService;
    }

    @Autowired
    @Lazy
    public void setExcelService(IExcelService excelService) {
        this.excelService = excelService;
    }
}
